import {Axis, PluginFunctionType, Point} from "../../nodeApp/static/lib/crowncad-plugin-sdk-0.0.1";
import {symmetryPoint} from "../util/Common";
import {Generator} from "./Generator";

/**
 * 齿轮创建
 */
class GearGenerator extends Generator {
  constructor() {
    super();
  }

  /**
   * 创建正齿轮
   */
  createSpurGear(spurGear, cb = () => {}) {
    const sketch = this.command.sketch;
    const solid = this.command.solid;
    this.createAddendumSketch(sketch, spurGear.ra);  // 创建草图 1
    const distance = this.createCutSketch(sketch, spurGear);  // 创建草图 2
    this.command.execute(true).then(() => {  // 执行
      this.command.clearCommand();
      this.createFillet(sketch, spurGear.toothFilterR, distance).then(() => {  // 创建草图圆角
        this.command.execute().then(() => {  // 执行
          this.command.clearCommand();
          this.extrudeAddendum(solid, spurGear.teethWidth).then(() => {  // 创建拉伸体
            this.command.execute().then(() => {  // 执行
              this.command.clearCommand();
              this.extrudeCut(solid, spurGear.teethWidth).then(() => {  // 创建切除体
                this.command.execute().then(() => {  // 执行
                  this.command.clearCommand();
                  this.circularPattern(solid, spurGear.teethNumber).then(() => {  // 创建圆周阵列
                    this.command.execute().then(() => {  // 执行
                      this.command.clearCommand();
                      cb();  // 加载完毕
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  }

  /**
   * 创建齿顶圆草图
   */
  createAddendumSketch(sketch, ra) {
    sketch.createSketch({sketchName: '草图1', datumId: 8});
    sketch.createCircle({centerPoint: new Point(0, 0), circlePoint: new Point(ra, 0)});
    sketch.exitSketch();
  }

  createInv(sketch, spurGear) {
    sketch.createSketch({sketchName: 'inv', datumId: 8});
    const alpha = 1 / (Math.cos(spurGear.rb / spurGear.rd));
    const invAlpha = Math.tan(alpha) - alpha;
    for (let r = spurGear.rb; r < spurGear.rd; r = r + 0.1) {
      sketch.createPoint({x: r * Math.cos(invAlpha), y: r * Math.sin(invAlpha)});
    }
    sketch.exitSketch();
  }

  /**
   * 创建分度圆、基圆、齿根圆草图
   * todo: 创建螺旋曲线，扫描切除
   */
  createRefSketch(sketch, spurGear) {
    sketch.createSketch({sketchName: '分度圆', datumId: 8});
    sketch.createCircle({centerPoint: new Point(0, 0), circlePoint: new Point(spurGear.rd, 0)});
    sketch.exitSketch();

    sketch.createSketch({sketchName: '基圆', datumId: 8});
    sketch.createCircle({centerPoint: new Point(0, 0), circlePoint: new Point(spurGear.rb, 0)});
    sketch.exitSketch();

    sketch.createSketch({sketchName: '齿根圆', datumId: 8});
    sketch.createCircle({centerPoint: new Point(0, 0), circlePoint: new Point(spurGear.rf, 0)});
    sketch.exitSketch();
  }

  /**
   * 创建拉伸切除草图
   */
  createCutSketch(sketch, spurGear) {
    sketch.createSketch({sketchName: '草图2', datumId: 8});
    const angle = Math.PI / 3;

    /*
    绘制两侧渐开线：
    获取右侧渐开线与分度圆交点 Q
    通过齿距弦长计算 OQ 与对称轴之间的角度 θ，得到 Q 在对称轴上的投影点 M
    以 OM 为对称轴，得到左侧渐开线
    */
    const QPoint = this.getIntersectionPointInInvolute(0, angle, spurGear.rb, (spurGear.rd + (spurGear.modification * spurGear.module)));
    const theta = Math.PI / (2 * spurGear.teethNumber);
    const mX = QPoint.x * Math.cos(theta) - QPoint.y * Math.sin(theta);
    const mY = QPoint.x * Math.sin(theta) + QPoint.y * Math.cos(theta);
    const MPoint = new THREE.Vector3(mX, mY);
    const OPoint = new THREE.Vector3(0, 0);

    // 齿根圆关键点与其对称点
    let pointF = this.getPoint({x: 0, y: spurGear.rf});
    let pointFS = this.getPoint(symmetryPoint(new THREE.Vector3(0, spurGear.rf), OPoint, MPoint));

    // 绘制渐开线
    const involuteRightPoints = [];
    const involuteLeftPoints = [];
    const increment = 0.05;
    if (spurGear.rb > spurGear.rf) {
      for (let i = 0; i < angle; i += increment) {
        const x = spurGear.rb * (Math.sin(i) - i * Math.cos(i));
        const y = spurGear.rb * (Math.cos(i) + i * Math.sin(i));
        involuteRightPoints.push(this.getPoint({x, y}));
        const symPoint = symmetryPoint(new THREE.Vector3(x, y), OPoint, MPoint);  // 对称点
        involuteLeftPoints.push(this.getPoint(symPoint));
      }
    } else {  // 齿根圆半径大于基圆半径，以齿根圆与渐开线交点为起点，绘制渐开线
      const interPoint = this.getIntersectionPointInInvolute(0, angle, spurGear.rb, spurGear.rf);
      pointF = this.getPoint(interPoint);
      pointFS = this.getPoint(symmetryPoint(new THREE.Vector3(interPoint.x, interPoint.y), OPoint, MPoint));
      involuteRightPoints.push(pointF);
      involuteLeftPoints.push(pointFS);
      for (let i = 0; i < angle; i += increment) {
        const x = spurGear.rb * (Math.sin(i) - i * Math.cos(i));
        const y = spurGear.rb * (Math.cos(i) + i * Math.sin(i));
        if (Math.sqrt(x * x + y * y) > spurGear.rf) {
          involuteRightPoints.push(this.getPoint({x, y}));
          const symPoint = symmetryPoint(new THREE.Vector3(x, y), OPoint, MPoint);
          involuteLeftPoints.push(this.getPoint(symPoint));
        }
      }
    }

    sketch.createIntpCurve({pickPoints: involuteRightPoints});
    sketch.createIntpCurve({pickPoints: involuteLeftPoints});

    // 两侧渐开线上顶点连线
    sketch.createSketchLine({
      startPoint: new Point(involuteLeftPoints[involuteLeftPoints.length - 1].x, involuteLeftPoints[involuteLeftPoints.length - 1].y),
      endPoint: new Point(involuteRightPoints[involuteRightPoints.length - 1].x, involuteRightPoints[involuteRightPoints.length - 1].y)
    });
    // 齿根圆
    sketch.createArcByCenter({
      centerPoint: new Point(0, 0),
      startPoint: pointF,
      endPoint: pointFS
    });

    const delta = Math.sqrt((involuteRightPoints[0].x - pointF.x) * (involuteRightPoints[0].x - pointF.x) +
      (involuteRightPoints[0].y - pointF.y) * (involuteRightPoints[0].y - pointF.y));
    if (delta > spurGear.toothFilterR) {
      // 渐开线与圆角连线
      sketch.createSketchLine({
        startPoint: new Point(involuteRightPoints[0].x, involuteRightPoints[0].y),
        endPoint: pointF
      });
      sketch.createSketchLine({
        startPoint: new Point(involuteLeftPoints[0].x, involuteLeftPoints[0].y),
        endPoint: pointFS
      });
    }
    sketch.exitSketch();

    return delta;
  }

  /**
   * 齿根圆圆角
   */
  createFillet(sketch, rho, dis) {
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.getElementsByFeatureNames, {featureNames: ['草图2']}).then(elements => {
        if (dis > rho) {
          let arcF, rLine, lLing;
          elements.elements.forEach(element => {
            if (element.params.type === 12) {
              arcF = element.id;
            }
            if (element.params.type === 10) {
              if (element.params.startPoint[0] === 0) {
                rLine = element.id;
              } else if (element.params.startPoint[0] < 0 && element.params.endPoint[0] < 0) {
                lLing = element.id;
              }
            }
          });
          sketch.editSketch({sketchName: '草图2'});
          sketch.createFilletCurve({curveId1: arcF, curveId2: rLine, radius: rho, type1: 2, type2: 2});
          sketch.createFilletCurve({curveId1: arcF, curveId2: lLing, radius: rho, type1: 2, type2: 2});
          sketch.exitEditSketch({sketchName: '草图2'});
        } else {
          let arcF, rInv, lInv;
          let tempElement;
          elements.elements.forEach(element => {
            if (element.params.type === 12) {
              arcF = element.id;
            }
            if (element.params.type === 15) {
              if (tempElement) {
                if (element.params.startPoint[0] > tempElement.params.startPoint[0]) {
                  rInv = element.id;
                  lInv = tempElement.id;
                } else {
                  rInv = tempElement.id;
                  lInv = element.id;
                }
              }
              tempElement = element;
            }
          });
          sketch.editSketch({sketchName: '草图2'});
          sketch.createFilletCurve({curveId1: arcF, curveId2: rInv, radius: rho, type1: 2, type2: 2});
          sketch.createFilletCurve({curveId1: arcF, curveId2: lInv, radius: rho, type1: 2, type2: 2});
          sketch.exitEditSketch({sketchName: '草图2'});
        }
        resolve();
      });
    });
  }

  /**
   * 获取基圆在 [startAngle, endAngle] 之间渐开线与目标圆的交点
   */
  getIntersectionPointInInvolute(startAngle, endAngle, baseR, targetR) {
    const midAngle = (startAngle + endAngle) / 2;
    const x = baseR * (Math.sin(midAngle) - midAngle * Math.cos(midAngle));
    const y = baseR * (Math.cos(midAngle) + midAngle * Math.sin(midAngle));
    const delta = Math.sqrt(x * x + y * y) - targetR;
    if (Math.abs(delta) < 0.001) {
      return {x, y};
    }
    if (delta > 0) {  // 二分中点在目标圆外部
      return this.getIntersectionPointInInvolute(startAngle, midAngle, baseR, targetR);
    } else if (delta < 0) {  // 二分中点在目标圆内部
      return this.getIntersectionPointInInvolute(midAngle, endAngle, baseR, targetR);
    }
  }

  /**
   * 创建齿顶圆拉伸体
   */
  extrudeAddendum(solid, teethWidth) {
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.getEntitiesByFeatureNames, {featureNames: ['草图1']}).then(res => {
        if (res?.entities) {
          solid.extrude({
            sketch: res.entities[0].id,
            height1: teethWidth + ''
          }, '拉伸凸台');
          resolve();
        }
      });
    });
  }

  /**
   * 创建切除体
   */
  extrudeCut(solid, teethWidth) {
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.getEntitiesByFeatureNames, {featureNames: ['草图2']}).then(res => {
        if (res?.entities) {
          this.request.execFunction(PluginFunctionType.getEntitiesByFeatureNames, {featureNames: ['拉伸凸台']}).then(extrudeRes => {
            if (extrudeRes?.entities) {
              solid.extrudeCut({
                sketch: res.entities[0].id, height1: teethWidth + '', cutSolids: [extrudeRes.entities[0]?.id]
              }, '拉伸切除');
              resolve();
            }
          });
        }
      });
    });
  }

  /**
   * 创建圆周阵列
   */
  circularPattern(solid, teethNumber) {
    const axis = new Axis();
    axis.setPoint(new Point(0, 0, 0), new Point(0, 0, 10));
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.GETFEATURESBYNAMES, {featureNames: ['拉伸切除']}).then(res => {
        if (res?.features) {
          solid.circularPattern({
            baseType: 1, features: [res.features[0]?.id], axis: axis, angle1: 360, instanceNum1: teethNumber,
          }, '圆周阵列');
          resolve();
        }
      });
    });
  }

  /**
   * 处理点坐标的误差
   */
  getPoint(point) {
    const x = Math.abs(point.x) < 1e-10 ? 0 : point.x;
    const y = Math.abs(point.y) < 1e-10 ? 0 : point.y;
    return new Point(x, y);
  }

  /**
   * 创建齿圈
   */
  createGearRing(spurGear, cb = () => {}) {
    const sketch = this.command.sketch;
    const solid = this.command.solid;
    this.createRingSketch(sketch, spurGear.ra);
    this.createRingTeeth(sketch, spurGear);
    this.command.execute(true).then(() => {  // 执行
      this.command.clearCommand();
          this.command.clearCommand();
          this.extrudeAddendum(solid, spurGear.teethWidth).then(() => {  // 创建拉伸体
            this.command.execute().then(() => {  // 执行
              this.command.clearCommand();
              this.extrudeRingGear(solid, spurGear.teethWidth).then(() => {  // 拉伸啮合齿
                this.command.execute().then(() => {  // 执行
                  this.command.clearCommand();
                  this.circularRingPattern(solid, spurGear.teethNumber).then(() => {  // 创建圆周阵列
                    this.command.execute().then(() => {  // 执行
                      this.command.clearCommand();
                      this.createBooleanUnion(solid).then(() => {
                        this.command.execute().then(() => {
                          cb();  // 加载完毕
                        })
                      })
                    });
                  });
                });
              });
            });
          });
        });
  }

  /**
   * 创建齿圈草图
   */
  createRingSketch(sketch, ra) {
    sketch.createSketch({sketchName: '草图1', datumId: 8});
    sketch.createCircle({centerPoint: new Point(0, 0), circlePoint: new Point(ra, 0)});
    sketch.createCircle({centerPoint: new Point(0, 0), circlePoint: new Point(ra + 5, 0)});
    sketch.exitSketch();
  }

  /**
   * 创建齿轮廓
   */
  createRingTeeth(sketch, spurGear) {
    sketch.createSketch({sketchName: '草图2', datumId: 8});
    const angle = Math.PI / 3;

    const QPoint = this.getIntersectionPointInInvolute(0, angle, spurGear.rb, (spurGear.rd + (spurGear.modification * spurGear.module)));
    const theta = Math.PI / (2 * spurGear.teethNumber);
    const mX = QPoint.x * Math.cos(theta) - QPoint.y * Math.sin(theta);
    const mY = QPoint.x * Math.sin(theta) + QPoint.y * Math.cos(theta);
    const MPoint = new THREE.Vector3(mX, mY);
    const OPoint = new THREE.Vector3(0, 0);

    // 齿根圆关键点与其对称点
    let pointF = this.getPoint({x: 0, y: spurGear.rf});
    let pointFS = this.getPoint(symmetryPoint(new THREE.Vector3(0, spurGear.rf), OPoint, MPoint));

    // 绘制渐开线
    const involuteRightPoints = [];
    const involuteLeftPoints = [];
    const increment = 0.05;
    if (spurGear.rb > spurGear.rf) {
      for (let i = 0; i < angle; i += increment) {
        const x = spurGear.rb * (Math.sin(i) - i * Math.cos(i));
        const y = spurGear.rb * (Math.cos(i) + i * Math.sin(i));
        involuteRightPoints.push(this.getPoint({x, y}));
        const symPoint = symmetryPoint(new THREE.Vector3(x, y), OPoint, MPoint);  // 对称点
        involuteLeftPoints.push(this.getPoint(symPoint));
        if (Math.sqrt(x * x + y * y) - spurGear.ra > 1) {
          break;
        }
      }
    } else {  // 齿根圆半径大于基圆半径，以齿根圆与渐开线交点为起点，绘制渐开线
      const interPoint = this.getIntersectionPointInInvolute(0, angle, spurGear.rb, spurGear.rf);
      pointF = this.getPoint(interPoint);
      pointFS = this.getPoint(symmetryPoint(new THREE.Vector3(interPoint.x, interPoint.y), OPoint, MPoint));
      involuteRightPoints.push(pointF);
      involuteLeftPoints.push(pointFS);
      for (let i = 0; i < angle; i += increment) {
        const x = spurGear.rb * (Math.sin(i) - i * Math.cos(i));
        const y = spurGear.rb * (Math.cos(i) + i * Math.sin(i));
        if (Math.sqrt(x * x + y * y) > spurGear.rf) {
          involuteRightPoints.push(this.getPoint({x, y}));
          const symPoint = symmetryPoint(new THREE.Vector3(x, y), OPoint, MPoint);
          involuteLeftPoints.push(this.getPoint(symPoint));
        }
        if (Math.sqrt(x * x + y * y) - spurGear.ra > 1) {
          break;
        }
      }
    }

    sketch.createIntpCurve({pickPoints: involuteRightPoints});
    sketch.createIntpCurve({pickPoints: involuteLeftPoints});

    // 两侧渐开线上顶点连线
    sketch.createSketchLine({
      startPoint: new Point(involuteLeftPoints[involuteLeftPoints.length - 1].x, involuteLeftPoints[involuteLeftPoints.length - 1].y),
      endPoint: new Point(involuteRightPoints[involuteRightPoints.length - 1].x, involuteRightPoints[involuteRightPoints.length - 1].y)
    });
    // 齿根圆
    sketch.createArcByCenter({
      centerPoint: new Point(0, 0),
      startPoint: pointF,
      endPoint: pointFS
    });

    const delta = Math.sqrt((involuteRightPoints[0].x - pointF.x) * (involuteRightPoints[0].x - pointF.x) +
      (involuteRightPoints[0].y - pointF.y) * (involuteRightPoints[0].y - pointF.y));
    if (delta > 0) {
      // 渐开线与圆角连线
      sketch.createSketchLine({
        startPoint: new Point(involuteRightPoints[0].x, involuteRightPoints[0].y),
        endPoint: pointF
      });
      sketch.createSketchLine({
        startPoint: new Point(involuteLeftPoints[0].x, involuteLeftPoints[0].y),
        endPoint: pointFS
      });
    }
    sketch.exitSketch();
  }

  /**
   * 拉伸齿圈齿条
   */
  extrudeRingGear(solid, teethWidth) {
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.getEntitiesByFeatureNames, {featureNames: ['草图2']}).then(res => {
        if (res?.entities) {
          this.request.execFunction(PluginFunctionType.getEntitiesByFeatureNames, {featureNames: ['拉伸凸台']}).then(res2 => {
            if (res2?.entities) {
              solid.extrude({
                sketch: res.entities[0].id,
                height1: teethWidth + '',
                mergeType: 1,
                mergeSolids: [res2.entities[0].id]
              }, '拉伸凸台2');
              resolve();
            }
          });
        }
      });
    });
  }

  /**
   * 创建圆周阵列
   */
  circularRingPattern(solid, teethNumber) {
    const axis = new Axis();
    axis.setPoint(new Point(0, 0, 0), new Point(0, 0, 10));
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.getEntitiesByFeatureNames, {featureNames: ['拉伸凸台2']}).then(res => {
        if (res?.entities) {
          solid.circularPattern({
            baseType: 0, body: res.entities[0].id, axis: axis, angle1: 360, instanceNum1: teethNumber,
          }, '圆周阵列');
          resolve();
        }
      });
    });
  }

  createBooleanUnion(solid) {
    return new Promise(resolve => {
      this.request.execFunction(PluginFunctionType.GETALLENTITIES).then(res => {
        if (res?.entities) {
          let entityIds = [];
          res.entities.forEach(item => {
            if (['拉伸凸台', '拉伸凸台2'].includes(item?.name) || item?.name.startsWith('圆周阵列')) {
              entityIds.push(item?.id);
            }
          });
          solid.booleanUnion({
            entitys: entityIds,
          }, '布尔交');
          return resolve();
        }
      });
    });
  }

}

const gearGenerator = new GearGenerator();
export {gearGenerator};
